home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 May / EnigmA AMIGA RUN 07 (1996)(G.R. Edizioni)(IT)[!][issue 1996-05][EARSAN CD VI].iso / docs / corsoguide / porte&messaggi-8.txt < prev    next >
Text File  |  1992-09-03  |  8KB  |  173 lines

  1. Le porte e i messaggi
  2.  
  3. I messaggi e le porte sono il vero mezzo che permettono l'intercomunicazione
  4. fra task e s.o. (i segnali servivano solo per avvertire riguardo ad un
  5. particolare evento ma non permettono di scambiare dati); le porte vengono
  6. create dai task e permettono di ricevere il messaggio spedito (sono delle
  7. "porte" sul mondo di intercomunicazione), che altro non è che un blocco di
  8. dati il cui puntatore viene passato al task che riceve il messaggio e
  9. tramite il quale può acquisire tutte le informazioni che il mittente vuole
  10. inviargli; questo mezzo fa uso dei segnali (per avvertire il task che un
  11. messaggio è arrivato, segnale che comunque viene gestito dal s.o. che quindi
  12. non necessita di essere allocato o gestito dal programmatore) ed inoltre
  13. viene molto utilizzato da Intuition. Pensate a questa similitudine per
  14. comprendere bene come funziona tutto il meccanismo: supponete che voi (il
  15. task) dopo una nottata passata a lavorare davanti al vostro Amiga volete
  16. dormire un po' di più la mattina e quindi staccate il telefono, ponete la
  17. sveglia all'orario giusto (i segnali) e vi mettete a dormire (stato di
  18. sleeping); la mattina però arriva il postino che bussa due volte (tipico
  19. segnale del postino da non confondere con il vicino che anche se suona il
  20. campanello, si vuole dormire e si fa finta di niente), quindi vi svegliate
  21. (stato attivo) e prelevate il messaggio aprendo la porta. Vi sono comunque
  22. delle puntualizzazioni sui messaggi da considerare: il messaggio è una
  23. struttura dati composta da alcune informazioni necessarie al sistema e dal
  24. messaggio vero e proprio; il messaggio deve essere spedito ad una precisa
  25. porta, viene passato per indirizzo e deve essere risposto, cioè quando il
  26. programma ne riceve uno deve rispondere al mittente per far capire che il
  27. messaggio è stato ricevuto, inoltre quelli arrivati ad una porta vengono
  28. mantenuti in una coda in modo che nessuno di questi venga perso.
  29. La porta come abbiamo detto è l'apertura sul mondo dei messaggi ed è
  30. identificata da questa struttura:
  31.  
  32. struct MsgPort
  33. {
  34.   struct Node mp_Node;
  35.   UBYTE mp_Flags;
  36.   UBYTE mp_SigBit;
  37.   struct Task *mp_SigTask;
  38.   struct List mp_MsgList;
  39. };
  40.  
  41. mp_Node serve perché tutte le porte vengono mantenute in una lista gestita
  42. dal s.o.; mp_Flags indica quale azione comporta l'arrivo di un messaggio a
  43. questa porta (vedere il riquadro); mp_SigBit è il numero di segnale
  44. utilizzato per segnalare al task che un messaggio è arrivato; mp_SigTask è
  45. il puntatore alla struttura task che indica il task a cui la porta è
  46. associata e che quindi deve essere segnalato (si possono creare più porte
  47. per un task); mp_SigTask può anche essere il puntatore ad una struttura
  48. Interrupt per la chiamata ad un interrupt software a seconda del valore di
  49. mp_Flags; mp_SigList è la lista dei messaggi arrivati alla porta che devono
  50. essere prelevati e risposti.
  51. Per creare una porta si utilizza la funzione CreatePort:
  52.  
  53. Porta = (struct MsgPort *)CreatePort(nome,priorità);
  54.  
  55. dove "nome" è il puntatore ad una stringa che identifica univocamente la
  56. porta e "priorità" è la priorità che la porta avrà sulle altre (normalmente
  57. 0), il valore ritornato Porta è il puntatore alla struttura MsgPort creata
  58. da CreatePort; questa funzione assegna automaticamente la porta alla lista
  59. pubblica delle porte tramite il nome "nome" che permette di identificarla;
  60. vi è dalla V36 del s.o. una funzione equivalente:
  61.  
  62. Porta = CreateMsgPort();
  63.  
  64. questa funzione però non inserisce la porta nella lista di utilizzo
  65. pubblico; per poterla inserire nella lista pubblica (quindi creata con
  66. CreateMsgPort) occorre utilizzare AddPort, e per rimuoverla RemPort. La
  67. possibilità di inserire la porta nella lista pubblica ne permette l'utilizzo
  68. anche ad altri programmi che possono ricercare l'indirizzo della sua
  69. struttura (per potergli lanciare un messaggio) mediante questa funzione:
  70.  
  71. Porta = (struct MsgPort *)FindPort(nome);
  72.  
  73. FindPort insieme alla funzione per spedire il messaggio devono essere usate
  74. insieme (vale a dire, prima di lanciare un messaggio ricercare sempre la
  75. porta) e precedute da una chiamata Forbid(); (funzione di exec che inibisce
  76. l'attività degli altri task) e seguite da Permit(); (per ritornare alla
  77. situazione normale dopo Forbid), questo perché il task che ha creato la
  78. porta, potrebbe rimuoverla in un qualsiasi momento. Per rimuovere la porta
  79. creata dopo che non serve più si utilizzano le corrispettive funzioni di
  80. quelle utilizzate DeletePort e DeleteMsgPort con queste sintassi:
  81.  
  82. DeletePort(Porta);
  83. DeleteMsgPrt(Porta); { V36 }
  84.  
  85. Illustriamo ora come i messaggi vengano inviati tramite le porte;
  86. innanzitutto, la struttura dati associata ad un messaggio è la seguente:
  87.  
  88. struct Message
  89. {
  90.   struct Node mn_Node;
  91.   struct MsgPort *mn_ReplyPort;
  92.   UWORD mn_Length;
  93. };
  94.  
  95. mn_Node serve perché i messaggi vengono mantenuti in una lista del s.o.;
  96. mn_ReplyPort è il puntatore alla porta che ha inviato il messaggio, a cui il
  97. programma deve rispondere dopo aver ricevuto quest'ultimo; mn_Length indica
  98. la lunghezza del messaggio compresa la struttura appena illustrata.
  99. Questa struttura indica solo le informazioni base per l'utilizzo del
  100. messaggio, ma il messaggio vero e proprio dove è, e che struttura ha? Il
  101. messaggio è situato nei bytes immediatamente successivi a quelli della
  102. struttura e possono avere qualsiasi forma vogliate e qualsiasi lunghezza
  103. (nei limiti imposti da mn_Length); per cui la forma di un ipotetico
  104. messaggio può essere questa:
  105.  
  106. struct Mio_Messaggio
  107. {
  108.   struct Message Mio_Msg;
  109.   ULONG Mio_Dato1,_MioDato2;
  110.   char Mio_Nome[20]; /* ecc... */
  111. };
  112.  
  113. la struttura Message deve quindi essere sempre presente in testa ad ogni
  114. messaggio.
  115. Per inviare un messaggio ad una porta occorre utilizzare la funzione di exec
  116. PutMsg:
  117.  
  118. PutMsg(porta,messaggio);
  119.  
  120. dove "porta" è il puntatore alla struttura MsgPort che identifica la porta a
  121. cui inviare il messaggio e "messaggio" è il puntatore alla struttura Message
  122. del messaggio da inviare; si consiglia di utilizzare questa funzione insieme
  123. a FindPort e di racchiuderle fra due chiamate Forbid() e Permit(), poiché il
  124. task della porta che riceve il messaggio, può decidere di chiuderla in un
  125. qualsiasi momento! Tramite la chiamata Forbid(), si impedisce il
  126. multitasking per cui il task non può fare nulla e tantomeno chiudere una
  127. porta; Permit() in ultimo riporta il sistema alla normalità. Qualche riga
  128. sopra è stato scritto si consiglia perché non è detto che sia sempre
  129. necessario comportarsi così; mettiamo infatti che il task proprietario
  130. della porta sia creato e messo in funzione dal vostro programma (che è un
  131. task a sua volta); in questo caso sapete benissimo a priori come questo si
  132. comporterà, e magari sarà il vostro programma a decidere quando fargli
  133. chiudere la porta, per cui il problema non si pone.
  134. Per attendere un messaggio, dovreste averlo capito dalla scorsa puntata,
  135. occorre utilizzare la funzione Wait; il codice del segnale per cui Wait deve
  136. attendere è presente nella struttura MsgPort della porta ché riceverà il
  137. segnale; per cui il codice con l'istruzione Wait per attendere il messaggio
  138. di una porta "porta" può avere la seguente forma:
  139.  
  140. struct MsgPort *porta;
  141. ULONG SegnPorta,segnali;
  142.   .
  143.   .
  144. SegnPorta = 1 << porta->mp_SigBit;
  145. segnali = Wait(SegnPorta);
  146.  
  147. Se però come nel caso appena descritto, l'evento per cui attendere è solo un
  148. messaggio, si può utilizzare una funzione che fa tuttò ciò automaticamente,
  149. passando semplicemente il puntatore alla porta per cui ricevere il
  150. messaggio:
  151.  
  152. messaggio = (struct Message *)WaitPort(porta);
  153.  
  154. "messaggio" è il puntatore alla struttura Message del messaggio arrivato
  155. alla porta; occorre ricordare che il sistema mantiene una lista FIFO (First
  156. In First Out, cioè il primo ad entrare è il primo ad uscire) di tutti i
  157. messaggi che arrivano alla porta per evitare che vadano persi; Wait e
  158. WaitPort non eliminano il messaggio dalla lista, per cui occorre utilizzare
  159. la funzione GetMsg() che ritorna anch'essa il puntatore del primo messaggio
  160. rimasto nella lista, eliminandolo però da quest'ultima (morale: "messaggio"
  161. ritornato da WaitPort non serve a nulla, poiché deve essere ripescato da
  162. GetMsg):
  163.  
  164. messaggio = (struct Message *)GetMsg(porta);
  165.  
  166. Come già accennato, bisogna rispondere ad ogni messaggio arrivato alla
  167. propria porta per segnalare che il messaggio è stato ricevuto correttamente,
  168. mediante la funzione ReplyMsg:
  169.  
  170. ReplyMsg(messaggio);
  171.  
  172. dove "messaggio" è il puntatore al messaggio a cui bisogna rispondere.
  173.